package net.lee.shiro.demo.config.shiro;

import net.lee.shiro.demo.realm.UserRealm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.SessionValidationScheduler;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.session.mgt.eis.SessionIdGenerator;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;

/**
 * Create by lishijun on 2018/4/11
 * Company: lianzhong
 * Domain:  ourgame.com
 * Department:Web Developer
 */
@Configuration
public class ShiroConfig {

    @Bean
    public SessionIdGenerator sessionIdGenerator() {
        return new JavaUuidSessionIdGenerator();
    }

    @Bean
    public SimpleCookie sessionIdCookie() {
        //设置前段保存身份信息的cookie 构造函数参数为cookie 的name
        SimpleCookie cookie = new SimpleCookie("sid");
        cookie.setHttpOnly(true);
        cookie.setMaxAge(-1);
        return cookie;
    }

    @Bean
    public SimpleCookie rememberMeCookie()
    {
        SimpleCookie cookie = new SimpleCookie("rememberMe");
        cookie.setHttpOnly(true);
        cookie.setMaxAge(259200);//30天
        return cookie;
    }

    @Bean
    public CookieRememberMeManager cookieRememberMeManager(SimpleCookie rememberMeCookie) throws Exception
    {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie);
        cookieRememberMeManager.setCipherKey("test123".getBytes("UTF-8"));
        return cookieRememberMeManager;
    }


    @Bean
    public SessionDAO sessionDAO(SessionIdGenerator sessionIdGenerator)
    {
        EnterpriseCacheSessionDAO sessionDAO = new EnterpriseCacheSessionDAO();
        sessionDAO.setSessionIdGenerator(sessionIdGenerator);
        sessionDAO.setActiveSessionsCacheName("shiro-activeSessionCache");
        return  sessionDAO;
    }

    /**
     *  需要注意 sessionValidationScheduler 与 sessionManager 配置相互引用的问题
     * @param sessionManager
     * @return
     */
    @Bean
    public SessionValidationScheduler sessionValidationScheduler(DefaultWebSessionManager sessionManager)
    {
        Quartz2SessionValidationScheduler quartz2SessionValidationScheduler = new Quartz2SessionValidationScheduler();
        quartz2SessionValidationScheduler.setSessionValidationInterval(1800000);
        sessionManager.setSessionValidationSchedulerEnabled(true);
        sessionManager.setSessionValidationScheduler(quartz2SessionValidationScheduler);
        sessionManager.setGlobalSessionTimeout(1800000);
        sessionManager.setDeleteInvalidSessions(true);
        quartz2SessionValidationScheduler.setSessionManager(sessionManager);
        return quartz2SessionValidationScheduler;
    }

    @Bean
    public DefaultWebSecurityManager securityManager(UserRealm userRealm, SessionManager sessionManager)
    {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);
        securityManager.setSessionManager(sessionManager);
        return securityManager;
    }

    @Bean
    public DefaultWebSessionManager sessionManager(SimpleCookie sessionIdCookie, SessionDAO sessionDAO)
    {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();

        sessionManager.setSessionDAO(sessionDAO);
        sessionManager.setSessionIdCookieEnabled(false);
        sessionManager.setSessionIdCookie(sessionIdCookie);
        return sessionManager;
    }

    /**
     * 认证方式注入，包括认证成功跳转 等功能，默认登陆页面设置等
     * 有如下几种方式  主要是 扩展 AuthenticationFilter 类实现的
     *    同一个接口   BasicHttpAuthenticationFilter
     *                FormAuthenticationFilter
     *
     *                PassThruAuthenticationFilter
     * @return
     */

    public FormAuthenticationFilter formAuthenticationFilter()
    {
        FormAuthenticationFilter formAuthenticationFilter = new FormAuthenticationFilter();
        formAuthenticationFilter.setLoginUrl("/login");
        formAuthenticationFilter.setPasswordParam("password");
        formAuthenticationFilter.setRememberMeParam("rememberme");
        formAuthenticationFilter.setUsernameParam("username");
        return  formAuthenticationFilter;
    }


    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor()
    {
        return  new LifecycleBeanPostProcessor();
    }



    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager)
    {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager);

        Map<String,Filter> filters = new HashMap<>();
        filters.put("authc",formAuthenticationFilter());
        bean.setFilters(filters);
        Map<String,String> filterChainDefinitions = new HashMap<>();
        filterChainDefinitions.put("/login","authc");
        filterChainDefinitions.put("/logout","logout");
        filterChainDefinitions.put("/authenticated","authc");
        filterChainDefinitions.put("/**","user");
        bean.setFilterChainDefinitionMap(filterChainDefinitions);
        return  bean;
    }


    /**
     * 认证拦截器
     * @param securityManager 安全管理器
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager)
    {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return  authorizationAttributeSourceAdvisor;
    }

    @Bean(name = "shiroFilter")
    public FilterRegistrationBean filterRegistrationBean(DefaultWebSecurityManager securityManager) throws Exception {
        FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
        //该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理
        filterRegistration.addInitParameter("targetFilterLifecycle", "true");
        filterRegistration.setFilter((Filter) shiroFilterFactoryBean(securityManager).getObject());
        filterRegistration.setEnabled(true);
        filterRegistration.addUrlPatterns("/*");
        return filterRegistration;
    }

}
